# -*-coding:utf8
import math
import string
import operator
import datetime
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from time import sleep
from functools import reduce
from public.common.globalconfig import *
import selenium.webdriver.support.ui as ui
from selenium.webdriver.common.touch_actions import TouchActions
from random import *
from selenium.webdriver.support.expected_conditions import *


class BasePage(object):
    '''
    公共方法封装
    '''

    def __init__(self, driver):
        try:
            self.driver = driver
            self.driver.maximize_window()
            self.Action = TouchActions(driver)
        except Exception:
            raise NameError('not Chrome')

    # 元素定位方法
    def findElement(self, element):
        '''
        元素定位二次封装，加入元素等待和元素可见控制
        :param element:元素定位--元组格式 element=(By.*，定位值，元素名称)
        :return:
        '''
        try:
            self.wait(30, element)
            elem = self.driver.find_element(element[0], element[1])
            self.scroll_bar(elem)
        except Exception as e:
            raise Exception(element[2] + '元素定位失败')
        return elem

    # 点击元素
    def click(self, element):
        '''
        点击元素
        :param element: 元素定位--元组格式 element=(By.*，定位值，元素名称)
        :return:
        '''
        try:
            self.findElement(element).click()
        except Exception as e:
            print(element[2] + '元素点击失败')
            raise

    # 文本输入
    def send(self, element, value):
        '''
        文本输入
        :param element: 元素定位--元组格式 element=(By.*，定位值，元素名称)
        :param value: 要输入的文本
        :return:
        '''
        try:
            self.findElement(element).clear()
            self.findElement(element).send_keys(value)
        except Exception as e:
            print(element[2] + '文本输入失败')
            raise

    # 获取文本
    def get_text(self, element):
        '''
        获取文本
        :param element: 元素定位--元组格式 element=(By.*，定位值，元素名称)
        :return:
        '''
        elem = self.findElement(element)
        try:
            return self.findElement(element).text
        except Exception as e:
            print(element[2] + '获取文本失败')
            raise

    def new_window(self, index):
        '''
        新建标签页面,index为新建窗口的次序
        :param index: 新建窗口的次序
        :return:
        '''
        newwindow = 'window.open()'
        self.driver.execute_script(newwindow)
        self.switch_window(index)

    def switch_window(self, index):
        '''
        窗口页面切换,index为要切换窗口句柄索引值
        :param index: 要切换窗口句柄索引值
        :return:
        '''
        handle = self.driver.window_handles
        self.driver.switch_to.window(handle[index])
        sleep(1)

    def get_tag_list(self, tag):
        '''
        获取指定标签名的元素集合
        :param tag: HTML 标签  例：div 、 span、 button等
        :return:
        '''
        return self.driver.find_elements_by_tag_name(tag)

    # 点击指定文本内容的元素

    def click_elem(self, text):
        '''
        点击指定文本内容的元素，界面可见的文本可使用该方法。
        :param text: 页面展示的文本
        :return:
        '''
        a = self.get_tag_list('div')
        tag = ['span', 'button', 'div', 'a']
        elem = []
        for i in a:
            if len(elem) == 0:
                for tag_type in tag:
                    if len(elem) == 0:
                        x = i.find_elements_by_tag_name(tag_type)
                        for o in x:
                            c = o.text
                            if c == text:
                                elem.append(o)
                                o.click()
                                break
                    else:
                        break
            else:
                break
        sleep(1)
        return elem

    def get_elem(self, text):
        '''
        获取指定文本内容的元素，界面可见的文本可使用该方法。
        :param text: 页面展示的文本
        :return:
        '''
        a = self.get_tag_list('div')
        tag = ['p', 'button', 'a', 'span', 'div']
        elem = []
        for i in a:
            if len(elem) == 0:
                for tag_type in tag:
                    if len(elem) == 0:
                        x = i.find_elements_by_tag_name(tag_type)
                        for o in x:
                            c = o.text
                            if text in c:
                                elem.append(o)
                                break
                    else:
                        break
            else:
                break
        sleep(1)
        return elem[0]

    def get_tablecels_text(self, elem, rownum, celnum):
        '''
        获得table中指定行列元素的文本
        :param elem: 表格元素定位
        :param rownum: 行数索引值
        :param celnum: 列数索引值
        :return:
        '''
        return self.get_tablecels(elem, rownum, celnum).text     # 索引值指定指定行列定位

    def get_tablecels(self, elem, rownum, celnum):
        '''
        获得页面表格中指定行列的元素
        :param elem: 表格元素定位--元组格式 element=(By.*，定位值，元素名称)
        :param rownum: 行数索引值
        :param celnum: 列数索引值
        :return:
        '''
        table = self.findElement(elem)
        table_rows = table.find_elements_by_tag_name(
            "tr")                       # 获取表格中所有行的定位
        return table_rows[int(rownum)].find_elements_by_tag_name('td')[
            int(celnum)]       # 索引值指定指定行列定位

    def get_attribute(self, element, name):
        '''获取元素值'''
        attribute = self.findElement(element).get_attribute(name)
        return attribute

    def get_title(self):
        '''获取当前页面标题'''
        try:
            title = self.driver.title
            return title
        except Exception as e:
            print('获取页面标题失败')
            raise

    # 全选
    def ctrl_a(self, element):
        self.findElement(element).send_keys(Keys.CONTROL, 'a')

    # 删除键
    def back_space(self, element):
        self.findElement(element).send_keys(Keys.BACK_SPACE)

    def select(self, element, value):
        '''
        下拉框选择
        :param element: 元素定位--元组格式 element=(By.*，定位值，元素名称)
        :param value: 要选择的选项值或文本
        :return:
        '''
        elem = self.findElement(element)
        try:
            if str(value).isdigit():
                Select(elem).select_by_value(value)
            elif str(value).isalpha():
                Select(elem).select_by_visible_text(value)
        except Exception as e:
            print(value + '：无法找到该值:')
            raise

    def wait(self, secend, element):
        '''
        元素等待限制
        :param secend: 等待时长
        :param element: 元素定位--元组格式 element=(By.*，定位值，元素名称)
        :return:
        '''
        try:
            wait = ui.WebDriverWait(self.driver, secend)
            wait.until(
                lambda driver: self.driver.find_element(
                    element[0], element[1]))
        except Exception as e:
            print(element[2] + '元素定位超时')
            raise

    def scroll_bar(self, elem):
        '''
        控制元素滚动至可见范围最底部
        :param elem: 元素定位--元组格式 element=(By.*，定位值，元素名称)
        :return:
        '''
        self.driver.execute_script("arguments[0].scrollIntoView(false);", elem)

    # 截图指定范围图片
    # def img_Screen_shot(self, imgname, range):
    #     '''
    #     截图指定范围图片
    #     :param imgname: 图片保存名称
    #     :param range: 截图范围
    #     :return:
    #     '''
    #     self.driver.save_screenshot(imgPath + '/' + imgname + '1.png')
    #     i = Image.open(imgPath + '/' + imgname + '1.png')
    #     aa2 = i.crop(range)
    #     aa2.save(imgPath + '/' + imgname + '.png')
    #
    # # 图片对比方法
    # def image_contrast(self, imgname, range=()):
    #     '''
    #     图片像素对比
    #     :param imgname:图片名称
    #     :param range:截图保存范围
    #     :return:
    #     '''
    #     if range != ():
    #         self.img_Screen_shot(imgname, range)
    #     image1 = Image.open(imgPath + '\\' + imgname + '.png')
    #     image2 = Image.open(check_img_path + '\\' + imgname + '.png')
    #     h1 = image1.histogram()
    #     h2 = image2.histogram()
    #     result = math.sqrt(reduce(operator.add, list(
    #         map(lambda a, b: (a - b) ** 2, h1, h2))) / len(h1))
    #     return result

    def window_handles(self):
        '''窗口句柄获取'''
        handle = self.driver.window_handles
        return handle

    # 弹窗确认

    def alert_accept(self):
        self.driver.switch_to_alert().accept()

    # 浏览器关闭
    def quit(self):
        self.driver.quit()

    # 标签关闭
    def Close(self):
        self.driver.close()

    def refresh(self):
        '''页面刷新'''
        self.driver.refresh()

    def slide_msite(self, elem, x, y):
        '''
        msite端模拟滑动操作
        :param elem: 元素定位--元组格式 element=(By.*，定位值，元素名称)
        :param x: 左右滑动，正值向左滑动，负值向右滑动
        :param y: 上下滑动，正值向上滑动，负值向下滑动
        :return:
        '''
        a = self.findElement(elem)
        self.Action.scroll_from_element(a, x, y).perform()
        # self.Action.release(x,y)

    def click_msite(self, element):
        '''
        msite端点击
        :param element:元素定位--元组格式 element=(By.*，定位值，元素名称)
        :return:
        '''
        try:
            self.Action.tap(self.findElement(element)).perform()
        except Exception as e:
            print(element[2] + '元素点击失败')
            raise

    def time_count(self, time1, time2):
        '''
        时间计算，传入两个时间参数，返回相差天数
        :param time1: 时间格式 %Y-%m-%d
        :param time2: 时间格式 %Y-%m-%d
        :return:
        '''
        c = datetime.datetime.strptime(time1, '%Y-%m-%d')
        d = datetime.datetime.strptime(time2, '%Y-%m-%d')
        if c > d:
            days = (c - d).days
        else:
            days = (d - c).days
        return days

    def close_windows(self):
        '''关闭多余页签,只保留第一个页签'''
        a = len(self.window_handles())
        b = 1
        if a != 0:
            for i in range(a - 1):
                self.switch_window(a - b)
                self.Close()
                if i == a - 2:
                    self.switch_window(0)
                else:
                    b += 1

    @staticmethod
    def random_email_num():
        '''生成随机邮箱'''
        ran_str = ''.join(sample(string.ascii_letters + string.digits, 8))
        email = str(ran_str) + '@test.com'
        return email


    def element_exist(self, elem):
        '''
        判断是否存在与dom树内，返回布尔值
        :param elem:
        :return:
        '''
        return presence_of_element_located(elem[1])

    @staticmethod
    def get_target_value(key, dic, tmp_list):   # 根据key获取返回数据（list或者dict）中对应value
        """
        :param key: 目标key值
        :param dic: JSON数据
        :param tmp_list: 用于存储获取的数据
        :return: list
        """
        if not isinstance(dic, dict) or not isinstance(tmp_list, list):  # 对传入数据进行格式校验
            return 'argv[1] not an dict or argv[-1] not an list '

        if key in dic.keys():
            tmp_list.append(dic[key])  # 传入数据存在则存入tmp_list

        for value in dic.values():  # 传入数据不符合则对其value值进行遍历
            if isinstance(value, dict):
                BasePage.get_target_value(key, value, tmp_list)  # 传入数据的value值是字典，则直接调用自身
            elif isinstance(value, (list, tuple)):
                BasePage.get_value(key, value, tmp_list)  # 传入数据的value值是列表或者元组，则调用_get_value

        return tmp_list

    @staticmethod
    def get_value(key, val, tmp_list):  # 根据key获取返回数据（list或者dict）中对应value
        for val_ in val:
            if isinstance(val_, dict):
                BasePage.get_target_value(key, val_, tmp_list)  # 传入数据的value值是字典，则调用get_target_value
            elif isinstance(val_, (list, tuple)):
                BasePage.get_value(key, val_, tmp_list)  # 传入数据的value值是列表或者元组，则调用自身
